package com.shop.om.conf.shiro;

import com.google.common.collect.Maps;
import com.jt.common.util.StringUtils;
import com.shop.om.listener.ShiroSessionListener;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.session.SessionListener;

import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.session.mgt.eis.SessionIdGenerator;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;

import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.*;

@Configuration
@Slf4j
public class ShrioConfig {

    //获取application.properties参数,此处不能加static关键字
    @Value("${redis.port}")
    private String redisPort;

    @Value("${redis.host}")
    private String redisHost;

    @Value("${redis.password}")
    private String redisPassword;


    /**
     * 注入shiro过滤工厂
     * @param securityManager
     * @return
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean =  new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        Map<String,String> map = Maps.newHashMap();
        //登出
        map.put("/logout", "logout");
        //对所有用户认证
        map.put("/**","authc");
        //不需要过滤配置
        map.put("/captcha.jpg","anon");
        map.put("/sys/login","anon");
        //登录
        //shiroFilterFactoryBean.setLoginUrl("/login");
        //首页
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //错误页面，认证不通过跳转
        shiroFilterFactoryBean.setUnauthorizedUrl("/error");
        //设置拦截规则
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    /**
     * 注入权限管理
     * @return
     */
    @Bean
    public DefaultWebSecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置自定义realm
        securityManager.setRealm(shiroRealm());
        //配置session
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }



    /**
     * 注入自定义realm
     * @return
     */
    @Bean
    public ShiroRealmConfig shiroRealm(){
        return  new ShiroRealmConfig();
    }

    //加入注解的使用，不加入这个注解不生效
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * sessionMannger
     */
    @Bean
    public ShiroSessionManager sessionManager(){
        ShiroSessionManager sessionManager =new ShiroSessionManager();
        sessionManager.setGlobalSessionTimeout(3600000);
        //是否定期检查Session的有效性
        sessionManager.setSessionValidationSchedulerEnabled(true);
        sessionManager.setSessionDAO(sessionDAO());
        sessionManager.setCacheManager(redisCacheManager());
        //设置session 监听
        Collection<SessionListener> listeners = new ArrayList<>();
        listeners.add(sessionListener());
        sessionManager.setSessionListeners(listeners);
        return sessionManager;
    }

    /**
     * 配置session监听
     * @return
     */
    @Bean("sessionListener")
    public ShiroSessionListener sessionListener(){
        ShiroSessionListener sessionListener = new ShiroSessionListener();
        return sessionListener;
    }

    /**
     * 配置会话ID生成器
     * @return
     */
    @Bean
    public SessionIdGenerator sessionIdGenerator() {
        return new JavaUuidSessionIdGenerator();
    }

    /**
     * SessionDAO的作用是为Session提供CRUD并进行持久化的一个shiro组件
     *  MemorySessionDAO 直接在内存中进行会话维护
     *  EnterpriseCacheSessionDAO  提供了缓存功能的会话维护，默认情况下使用MapCache实现，内部使用ConcurrentHashMap保存缓存的会话。
     *
     * @return
     */
    @Bean
    public SessionDAO sessionDAO(){
        EnterpriseCacheSessionDAO sessionDAO =  new EnterpriseCacheSessionDAO();
        //设置session缓存的名字 默认为 shiro-activeSessionCache
        sessionDAO.setActiveSessionsCacheName("shiro-activeSessionCache");
        //sessionId生成器
        //sessionDAO.setSessionIdGenerator(sessionIdGenerator());

        return sessionDAO;
    }


    @Bean
    public RedisManager redisManager(){
        log.info("shiro 链接redis ");
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(redisHost +":"+redisPort);
        redisManager.setDatabase(0);
        if (!StringUtils.isBlank(redisPassword)){
            redisManager.setPassword(redisPassword);
        }
        return redisManager;
    }

    /**
     * cacheManager 缓存 redis实现
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    public RedisCacheManager redisCacheManager() {
        log.info("===============(3)创建缓存管理器RedisCacheManager");

        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        //redis中针对不同用户缓存(此处的id需要对应user实体中的id字段,用于唯一标识)
        redisCacheManager.setPrincipalIdFieldName("id");
        //用户权限信息缓存时间
        redisCacheManager.setExpire(20000);
        return redisCacheManager;
    }


}
